package org.example.system.filter;

import cn.hutool.captcha.generator.CodeGenerator;
import cn.hutool.core.util.StrUtil;
import org.example.system.common.constant.SecurityConstants;
import org.example.system.common.result.ResultCode;
import org.example.system.common.util.ResponseUtils;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;


/**
 * 图形验证码校验过滤器
 *
 * @author LY
 */
public class CaptchaValidationFilter extends OncePerRequestFilter {

    private static final AntPathRequestMatcher LOGIN_PATH_REQUEST_MATCHER =
        new AntPathRequestMatcher(org.example.system.security.constant.SecurityConstants.LOGIN_PATH, "POST");

    public static final String CAPTCHA_CODE_PARAM_NAME = "captchaCode";
    public static final String CAPTCHA_KEY_PARAM_NAME = "captchaKey";

    private final RedisTemplate<String, Object> redisTemplate;
    private final CodeGenerator codeGenerator;

    public CaptchaValidationFilter(RedisTemplate<String, Object> redisTemplate, CodeGenerator codeGenerator) {
        if (redisTemplate == null || codeGenerator == null) {
            throw new IllegalArgumentException("RedisTemplate and CodeGenerator must not be null");
        }
        this.redisTemplate = redisTemplate;
        this.codeGenerator = codeGenerator;
    }

    @Override
    public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {
        if (!isLoginRequest(request)) {
            chain.doFilter(request, response);
            return;
        }

        String captchaCode = request.getParameter(CAPTCHA_CODE_PARAM_NAME);
        if (StrUtil.isBlank(captchaCode)) {
            chain.doFilter(request, response);
            return;
        }

        String verifyCodeKey = request.getParameter(CAPTCHA_KEY_PARAM_NAME);
        if (StrUtil.isBlank(verifyCodeKey)) {
            ResponseUtils.writeErrMsg(response, ResultCode.VERIFY_CODE_TIMEOUT);
            return;
        }

        validateCaptcha(response, verifyCodeKey, captchaCode, chain, request);
    }

    private boolean isLoginRequest(HttpServletRequest request) {
        return LOGIN_PATH_REQUEST_MATCHER.matches(request);
    }

    private void validateCaptcha(HttpServletResponse response, String verifyCodeKey, String captchaCode,
            FilterChain chain, HttpServletRequest request) throws IOException, ServletException {
        String cacheVerifyCode = (String) redisTemplate.opsForValue()
            .get(SecurityConstants.CAPTCHA_CODE_PREFIX + verifyCodeKey);

        if (cacheVerifyCode == null) {
            ResponseUtils.writeErrMsg(response, ResultCode.VERIFY_CODE_TIMEOUT);
            return;
        }

        if (codeGenerator.verify(cacheVerifyCode, captchaCode)) {
            chain.doFilter(request, response);
        } else {
            ResponseUtils.writeErrMsg(response, ResultCode.VERIFY_CODE_ERROR);
        }
    }
}
